package com.yiren.dbaa.module.help_center.api.services;

import android.app.Activity;
import android.util.Log;

import com.blankj.utilcode.util.EncodeUtils;
import com.blankj.utilcode.util.LogUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yiren.backstage.communication.api.AbstractCommunication;
import com.yiren.backstage.communication.api.impl.BluetoothCommunicationApiImpl;
import com.yiren.backstage.communication.api.impl.SerialCommunicationApiImpl;
import com.yiren.backstage.communication.interfaces.DataCallback;
import com.yiren.backstage.communication.utils.MessagesUtil;
import com.yiren.backstage.currency.constant.SignalGConstant;
import com.yiren.backstage.currency.utils.FileUtil;
import com.yiren.backstage.currency.utils.StringUtil;
import com.yiren.dbaa.currency.api.CommonCallBack;
import com.yiren.dbaa.constant.AddressConstant;
import com.yiren.dbaa.constant.G;
import com.yiren.dbaa.constant.StringConstant;
import com.yiren.dbaa.net.oss.IOssFileOperationApi;
import com.yiren.dbaa.net.interf.OssFileCallback;
import com.yiren.dbaa.net.oss.impl.OssFileOperationApiImpl;
import com.yiren.dbaa.module.help_center.bean.DeviceUpdateBean;
import com.yiren.dbaa.module.help_center.bean.FileDownloadBean;
import com.yiren.dbaa.module.device.contract.DeviceConnectContract;
import com.yiren.dbaa.module.device.model.DeviceConnectModel;
import com.yiren.dbaa.module.device.util.HardwareUpdatePathUtil;
import com.yiren.dbaa.net.OkHttpUtils;
import com.yiren.dbaa.net.bean.BaseResponseBean;
import com.yiren.dbaa.net.interf.StringCallback;
import com.yiren.dbaa.util.ZipUtils;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.util.Map;

/**
 * Created by WANGRONGXIANG
 * on 2022/6/13
 * Describe
 */
public class HardwareUpdateService {

    private final String TAG = "HardwareUpdateModel";
    private Activity activity;
    private IOssFileOperationApi iOssFileOperationApi;
    private DeviceConnectContract.Model deviceConnectModel;
    private AbstractCommunication abstractCommunication;
    private int updateI = 1; //更新程序所用的循环i
    private int upNum;

    public HardwareUpdateService(Activity activity) {
        this.activity = activity;
        iOssFileOperationApi = new OssFileOperationApiImpl(activity);
        deviceConnectModel = new DeviceConnectModel(activity);
        if (SignalGConstant.isOpen) {
            abstractCommunication = BluetoothCommunicationApiImpl.getInstance(activity);
        } else {
            abstractCommunication = SerialCommunicationApiImpl.getInstance(activity);
        }
    }

    /**
     * 获取软硬件下载路径
     */
    public void getFileDownloadUrl(CommonCallBack callBack) {
        OkHttpUtils.getInstance().getStringByAsync(activity, AddressConstant.getFileDownloadUrl(), new StringCallback() {
            @Override
            public void getString(String result) {
                BaseResponseBean<FileDownloadBean> responseBean = new Gson().fromJson(result, new TypeToken<BaseResponseBean<FileDownloadBean>>() {
                }.getType());
                if (null == responseBean.getError()) {
                    FileDownloadBean fileDownloadBean = responseBean.getResult();
                    if (null != fileDownloadBean) {
                        if (StringUtils.isNotEmpty(fileDownloadBean.getEnvironment()) && StringUtils.equals("1", fileDownloadBean.getEnvironment())) {
                            if (StringUtils.isNotEmpty(fileDownloadBean.getSoftwareUrl())) {
                                // 软件地址有更新
                                AddressConstant.APK_UPDATE_URL = fileDownloadBean.getSoftwareUrl().replaceAll("(.*)/(.*?)/(.*?)/(.*)", "$1");
                                AddressConstant.APK_PATH = fileDownloadBean.getSoftwareUrl();
                                for (int i = 0; i < 3; i++) {
                                    AddressConstant.APK_PATH = AddressConstant.APK_PATH.substring(AddressConstant.APK_PATH.indexOf("/") + 1);
                                }
                                AddressConstant.APK_PATH = AddressConstant.APK_PATH.replaceAll("(.*)/(.*)", "$1") + "/";
                                AddressConstant.APK_CONFIG_URL = fileDownloadBean.getSoftwareUpdateStatement();
                                for (int i = 0; i < 3; i++) {
                                    AddressConstant.APK_CONFIG_URL = AddressConstant.APK_CONFIG_URL.substring(AddressConstant.APK_CONFIG_URL.indexOf("/") + 1);
                                }
                            }
                            if (StringUtils.isNotEmpty(fileDownloadBean.getHardwareUrl())) {
                                // 硬件地址有更新
                                AddressConstant.APK_UPDATE_URL = fileDownloadBean.getHardwareUrl().replaceAll("(.*)/(.*?)/(.*?)/(.*)", "$1");
                                AddressConstant.HOST_MACHINE_PATH = fileDownloadBean.getHardwareUrl();
                                for (int i = 0; i < 3; i++) {
                                    AddressConstant.HOST_MACHINE_PATH = AddressConstant.HOST_MACHINE_PATH.substring(AddressConstant.HOST_MACHINE_PATH.indexOf("/") + 1);
                                }
                                AddressConstant.HOST_MACHINE_PATH = AddressConstant.HOST_MACHINE_PATH.replaceAll("(.*)/(.*)", "$1") + "/";
                                AddressConstant.HOST_MACHINE_CONFIG_URL = fileDownloadBean.getHardwareUpdateStatement();
                                for (int i = 0; i < 3; i++) {
                                    AddressConstant.HOST_MACHINE_CONFIG_URL = AddressConstant.HOST_MACHINE_CONFIG_URL.substring(AddressConstant.HOST_MACHINE_CONFIG_URL.indexOf("/") + 1);
                                }
                                callBack.success("");
                            }
                        }
                    }
                }
            }
        });
    }


    /**
     * 获取硬件升级服务器包路径
     */
    public String getUpgradesPath() {
        String hardwareUpgradesPath = "";
        if (null != G.connectDeviceMessage) {
            hardwareUpgradesPath = HardwareUpdatePathUtil.getPackageObjectKey();
        } else {
            for (Map.Entry<Integer, String> integerStringEntry : SignalGConstant.mapValue.entrySet()) {
                Integer key = integerStringEntry.getKey();
                if (key.equals(MessagesUtil.PARAM)) {
                    String value = integerStringEntry.getValue();
                    G.connectDeviceMessage = deviceConnectModel.analysisDeviceData(value);
                    break;
                }
            }
            if (G.connectDeviceMessage != null) {
                hardwareUpgradesPath = HardwareUpdatePathUtil.getPackageObjectKey();
            }
        }
        return hardwareUpgradesPath;
    }

    /**
     * 获取硬件升级服务器说明文件路径
     */
    public String getUpgradesInstructions() {
        String hardwareUpgradesInstructions = "";
        if (null != G.connectDeviceMessage) {
            hardwareUpgradesInstructions = HardwareUpdatePathUtil.getConfigObjectKey();
        } else {
            for (Map.Entry<Integer, String> integerStringEntry : SignalGConstant.mapValue.entrySet()) {
                Integer key = integerStringEntry.getKey();
                if (key.equals(MessagesUtil.PARAM)) {
                    String value = integerStringEntry.getValue();
                    G.connectDeviceMessage = deviceConnectModel.analysisDeviceData(value);
                    break;
                }
            }
            if (G.connectDeviceMessage != null) {
                hardwareUpgradesInstructions = HardwareUpdatePathUtil.getConfigObjectKey();
            }
        }
        return hardwareUpgradesInstructions;
    }

    /**
     * 异步数据记事本下载 无需凭证 直接返回文本内容
     *
     * @param objectKey
     */
    public void ossTxtDownload(String objectKey, CommonCallBack callBack) {
        iOssFileOperationApi.downLoadTxtFile(StringConstant.DJ_APK, objectKey, new OssFileCallback() {
            @Override
            public void success(String result) {
                DeviceUpdateBean deviceUpdateBean = new Gson().fromJson(result, DeviceUpdateBean.class);
                callBack.success(deviceUpdateBean);
            }

            @Override
            public void fail(String error) {
                callBack.fail(error);
            }
        });
    }


    /**
     * 带进度条下载
     *
     * @param bucketName OSS地址
     * @param objectKey  OSS文件名称
     * @param fileUrl    下载URL
     * @param fileName   下载文件名称
     */
    public void downLoadFileProcess(String bucketName, String objectKey, String fileUrl, String fileName, OssFileCallback callback) {
        iOssFileOperationApi.downLoadFile(bucketName, objectKey, fileUrl, fileName, callback);
    }

    /**
     * 更新下位机程序
     *
     * @param apkName
     * @param callBack
     */
    public void hdUpdate(String apkName, CommonCallBack callBack) {
        //远程数据 文件
        String hdUpdatePath = FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate";
        File myFile = new File(hdUpdatePath);
        if (myFile.exists()) {
            // 开始解压更新文件
            ZipUtils.unpackZip(FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate/" + apkName,
                    FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate", true);
            File file = new File(FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate");
            String[] list = file.list();
            if (!list[0].equalsIgnoreCase("DiJia1.bin")) {
                upNum = list.length / 2;
                if (upNum < 1) {
                    return;
                }
            }
        }
        callBack.success("");
    }


    /**
     * 更新下位机
     */
    public void toUpgrade(CommonCallBack callBack) {
        MessagesUtil messageRd = new MessagesUtil(MessagesUtil.REBOOT, 0, new byte[0], new byte[0]);
        abstractCommunication.writeData(messageRd.getMessage(), "RE_REBOOT", new DataCallback() {
            @Override
            public void onSendReadData(String data) {
                if (StringUtils.isNotEmpty(data))
                    callBack.success(data);

                else
                    callBack.fail("升级失败，请重试！");
            }
        });
    }

    /**
     * 开始更新新主机发送数据
     */
    public void startUpdateNewHost(CommonCallBack callBack) {
        new Thread(() -> {
            try {
                // 如果当前map存在这个键值对就移除
                if (null != SignalGConstant.mapValue.get(11)) {
                    SignalGConstant.mapValue.remove(11);
                }
                String connection = "7F7F7F7F7F";
                byte bys[] = new byte[connection.length() / 2];
                for (int i = 0; i < connection.length(); i = i + 2) {
                    bys[i / 2] = (byte) Integer.parseInt(connection.substring(i, i + 2), 16);
                }
                while (null == SignalGConstant.mapValue.get(11)) {
                    abstractCommunication.writeData(bys, null, null);
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 接收到第一步的结果
                String a0 = SignalGConstant.mapValue.get(11);
                if (a0.equals("41")) {// 超时
                    // 升级失败，请检查串口是否连接正常
                    callBack.fail("failure");
                } else {  // 成功
                    /**
                     *  向模块发送固件长度，模块接收成功返回0xA1(需等待30ms)。如果返回0x51则表示数据格式错误。
                     */
                    // 获取文件路径
                    String pathString = FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate/DiJia1.bin";
                    byte[] binFileToBytes = FileUtil.FileToBytes(pathString);
                    LogUtils.d(TAG + "obd升级文件的长度 " + binFileToBytes.length);
                    String dd = Integer.toHexString(binFileToBytes.length);
                    String string;
                    if (dd.length() > 4) {
                        dd = dd.substring(dd.length() - 4, dd.length());
                    } else if (dd.length() == 3) {
                        dd = "0" + dd;
                    } else if (dd.length() == 2) {
                        dd = "00" + dd;
                    } else if (dd.length() == 1) {
                        dd = "000" + dd;
                    }
                    System.out.println(dd);
                    string = "0005" + dd.substring(0, 2) + dd.substring(2, dd.length());
                    string = string + StringUtil.makeChecksum(string);
                    Log.e("固件长度", "" + string);
                    byte by1[] = new byte[string.length() / 2];
                    for (int i = 0; i < string.length(); i = i + 2) {//00057cae2f
                        by1[i / 2] = (byte) Integer.parseInt(string.substring(i, i + 2), 16);
                    }
                    // 如果当前map存在这个键值对就移除
                    if (null != SignalGConstant.mapValue.get(12)) {
                        SignalGConstant.mapValue.remove(12);
                    }
                    LogUtils.d(TAG + " 固件长度 " + ArrayUtils.toString(by1));
                    abstractCommunication.writeData(by1, null, null);
                    while (null == SignalGConstant.mapValue.get(12)) {
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 接收到第二步的结果
                    String a1 = SignalGConstant.mapValue.get(12);
                    if (a1.equals("41") || a1.equals("51")) {// 超时或者数据格式错误
                        // 升级失败，请检查串口是否连接正常
                        callBack.fail("failure");
                    } else {
                        /**
                         *  向模块发送一帧数据，模块接收成功返回0xA2,模块接收成功返回0xA3后表示升级完成。如果返回0x52则表示数据格式错误。
                         */
//							byte[] binFileToBytes = FileUtil.FileToBytes(pathString);
                        // 第几份
                        int subscript = 0;
                        // 多少份
                        int binFileToByteslength;
                        if (binFileToBytes.length % 512 == 0) {
                            binFileToByteslength = binFileToBytes.length / 512;
                        } else {
                            binFileToByteslength = (binFileToBytes.length / 512) + 1;
                        }
                        while (subscript <= binFileToByteslength) {
                            StringBuilder stringBuilder = new StringBuilder("");
                            for (int i = subscript * 512; i < binFileToBytes.length; i++) {
                                if (i == (subscript + 1) * 512) {
                                    break;
                                }
                                int v = binFileToBytes[i] & 0xFF;
                                String hv = Integer.toHexString(v);
                                if (hv.length() < 2) {
                                    stringBuilder.append(0);
                                }
                                stringBuilder.append(hv);
                            }
                            subscript++;
                            Log.e("包大小", "subscript：" + subscript + " ----- 包长度" + binFileToBytes.length);
                            /*
                             *  每次发送的值
                             */
                            // 总长度
                            String numlength = Integer.toHexString(stringBuilder.length() / 2 + 3);
                            if (numlength.length() > 4) {
                                numlength = numlength.substring(numlength.length() - 4, numlength.length());
                            } else if (numlength.length() == 3) {
                                numlength = "0" + numlength;
                            } else if (numlength.length() == 2) {
                                numlength = "00" + numlength;
                            } else if (numlength.length() == 1) {
                                numlength = "000" + numlength;
                            }
                            String a3String = numlength.substring(0, 2) + numlength.substring(2) + stringBuilder;
                            a3String = a3String + StringUtil.makeChecksum(a3String);
                            Log.e("每次发送的值", "总长度：" + numlength + "-----前四个数值：" + a3String.substring(0, 4) + "-----最后的校验：" + a3String.substring(a3String.length() - 2, a3String.length()));
                            byte by2[] = new byte[a3String.length() / 2];
                            for (int i = 0; i < a3String.length(); i = i + 2) {
                                by2[i / 2] = (byte) Integer.parseInt(a3String.substring(i, i + 2), 16);
                            }
                            // 如果当前map存在这个键值对就移除
                            if (null != SignalGConstant.mapValue.get(13)) {
                                SignalGConstant.mapValue.remove(13);
                            }
//                                System.out.println("bbbbbbbbbbs:" + by2.length);
                            LogUtils.d(TAG + subscript + " == " + binFileToByteslength + "数据: " + ArrayUtils.toString(by2));
                            // 发送数据
                            abstractCommunication.writeData(by2, null, null);
                            // 查看下位机是否返回接收成功
                            while (null == SignalGConstant.mapValue.get(13)) {
                                try {
                                    Thread.sleep(20);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            // 接收到第三步的结果
                            String a2 = SignalGConstant.mapValue.get(13);
                            if (a2.equals("41") || a2.equals("52")) {// 超时或者数据格式错误
                                // 升级失败，请检查串口是否连接正常
                                callBack.fail("failure");
                            } else if (a2.equals("A3")) {// 升级成功
                                callBack.success("");
                                LogUtils.d(TAG + "升级发送数据成功");
                                break;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                Log.e("升级发送数据异常", "" + e.getMessage());
                e.printStackTrace();
            }
        }).start();
    }

    /**
     * 开始更新老主机发送数据
     *
     * @param callBack
     */
    public void startUpdateOldHost(CommonCallBack callBack) {
        new Thread(() -> {
            //等待下位机重启的过程，2秒足够下位机重启
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            File binFile = new File(FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate/" + "DiJia" + updateI + ".bin");
            File sigFile = new File(FileUtil.fetchAvailableSdcardFoloder() + "/yiren/dbaf/hdUpdate/" + "DiJia" + updateI + ".bin.sign");
            if (binFile.exists() && sigFile.exists()) {
                //下载并解压成功，开始向下位机发送升级的程序
                byte[] binFileToBytes = FileUtil.FileToBytes(binFile.getPath());
                byte[] sigFileToBytes = FileUtil.FileToBytes(sigFile.getPath());
                int updateTemp = 0;
                // 所有文件是否发送完成（upNum文件个数）
                if (!(updateI < upNum)) {
                    updateTemp = 1;
                }
                //开始发送升级包
                MessagesUtil messageUPD = new MessagesUtil(MessagesUtil.UPDATE, updateTemp, binFileToBytes, EncodeUtils.base64Decode(new String(sigFileToBytes)));
                abstractCommunication.writeData(messageUPD.getMessage(), "RE_UPDATE", new DataCallback() {
                    @Override
                    public void onSendReadData(String data) {
                        //删除更新包文件
                        binFile.delete();
                        sigFile.delete();
                        if (StringUtils.isEmpty(data)) {
                            //如果下位机通讯类返回时超时了，就返回一个failg告知这里升级失败了
                            //更新出错了，退出更新循环
                            callBack.fail(null);
                        } else {
                            String[] split = data.split(";");
                            String version = split[2];
                            if (!version.equals("FAILED")) {
                                System.out.println("升级成功!");
                                if (updateI < upNum) {
                                    callBack.success("");
                                    updateI++;
                                } else {
                                    callBack.success("更新完成");
                                }
                            } else {
                                System.out.println("升级失败!");
                                callBack.fail(null);
                                return;
                            }
                        }
                    }
                });
            }
        }).start();
    }

}
